#include <time.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include "GameModel.h"
#include "../Logger/Logger.h"
const int GameModel::SHUFFLE_TIME_ = 80;
const int GameModel::MAX_PLAYERS_NUM_ = 15;
const int GameModel::CARDS_NUM_ = 75;
const int GameModel::USUAL_CARDS_NUM_ = 72;
const int GameModel::ARROWS_INSIDE_CARDS_NUM_ = 3;
const int GameModel::EVERY_CARD_TYPE_NUM_ = 4;
const int GameModel::ARROWS_INSIDE_ID_ = USUAL_CARDS_NUM_ / EVERY_CARD_TYPE_NUM_;

int GameModel::getTurn()
{
  bool flag = false;  
  int start = currentTurn_;

  while (!flag)
  {
    if (players_[currentTurn_].getClosedCardsNumber() != 0)
    {
      flag = true; 
    }
    else
    {
      currentTurn_++;
      if (currentTurn_ > playersNumber_)
      {
        currentTurn_ = 1;
      }
      if (currentTurn_ == start)
      {
        break;
      }
    }
  }

  if (!flag)
  {
    currentTurn_ = 0;
  }
  return currentTurn_;
}

int GameModel::findWinner()
{
  for (int i = 1; i <= playersNumber_; ++i)
  {
    if (players_[i].isWinner())
    {
      whoIsWinner_ = i;
      isGameStarted_ = false;
      return 0;
    }
  }
  return 1;
}

void GameModel::shuffle()
{
  srand(time(0));
  int toSwap = 0;
  for (int j = 0; j < SHUFFLE_TIME_; ++j)
  {
    for (int i = 0; i < CARDS_NUM_; ++i)
    {
      std::swap(cards_[i], cards_[rand() % CARDS_NUM_]);
    }
  }
  //std::random_shuffle(cards_.begin(), cards_.end());
}

void GameModel::distribute()
{
  int cardsToDistribute = CARDS_NUM_ - CARDS_NUM_ % playersNumber_;
   

  //cards to players
  for (int i = 0, j = 1; i < cardsToDistribute; ++i)
  {
    players_[j].addCardToClosedTop(cards_[i]);
    ++j;
    if (j > playersNumber_)
    {
      j = 1;
    }
  }
  
    //cards under totem
  for (int i = cardsToDistribute; i < CARDS_NUM_; ++i)
  {
    players_[0].addCardToOpenedTop(cards_[i]);
  }
  currentTurn_ = 1;   
}

void GameModel::zeroDuelists()
{
  duelWinner_ = 0;
  duelLooser_ = 0;
  wrongDuelist_ = 0;
}

GameModel::GameModel():playersNumber_(0), whoIsWinner_(0), isGameStarted_(false), duelStarted_(false), 
                       currentTurn_(0), arrowsInsideFlag_(0), duelWinner_(0), duelLooser_(0), wrongDuelist_(0)
{
  players_.resize(MAX_PLAYERS_NUM_ + 1);
  
  cards_.resize(CARDS_NUM_);
  for (int i = 0; i != USUAL_CARDS_NUM_; ++i)
  {
    cards_[i].setID(i / EVERY_CARD_TYPE_NUM_);
    cards_[i].setColor(i % EVERY_CARD_TYPE_NUM_);
  }

  //int arrowsInsideID = USUAL_CARDS_NUM_ / EVERY_CARD_TYPE_NUM_;
  int arrowsInsideColor = EVERY_CARD_TYPE_NUM_;

  for (int i = USUAL_CARDS_NUM_; i != USUAL_CARDS_NUM_ + ARROWS_INSIDE_CARDS_NUM_ ; ++i)
  {
    cards_[i].setID(ARROWS_INSIDE_ID_);
    cards_[i].setColor(arrowsInsideColor);
  }
}

int GameModel::addPlayer(const std::string &name, const time_t &connectTime, int &error)
{
  //log("start adding");
  if (isGameStarted_)
  {
    error =  2;
    return 0;
  }
  if (playersNumber_ >= MAX_PLAYERS_NUM_)
  {
    error = 1;
    return 0;
  }
  else
  {
    ++playersNumber_;
    //log(playersNumber_, DEBUG);
    //log(players_.size(),DEBUG);
    players_[playersNumber_].setName(name);
    //log(name);
    //log("isAdded");
    players_[playersNumber_].setConnectTime(connectTime);
  }
  //log("end adding");
  return playersNumber_;
}

int GameModel::openCard(int playerNum)
{
  zeroDuelists();
  duelStarted_ = false;
  
  if ((playerNum > playersNumber_) || (playerNum <= 0))
  {
    return 0;
  }

  players_[playerNum].openCard();

  ++currentTurn_;

  if (currentTurn_ > playersNumber_)
  {
    currentTurn_ = 1;
  }

  getTurn();
  
  if (getTopCardID(playerNum) == ARROWS_INSIDE_ID_)
  {
     arrowsInsideFlag_ = playerNum;
  }
  else if (currentTurn_ == 0)
  {
    isGameStarted_ = false;
    whoIsWinner_ = 0;
  }

  return currentTurn_;
}


int GameModel::getTotem(int playerNum)
{
  zeroDuelists();
  if(duelStarted_)
  {
    return currentTurn_;
  }
 
  duelStarted_ = true;
  if ((playerNum > playersNumber_) || (playerNum <= 0))
  {
    return 0;
  }

  if (arrowsInsideFlag_ != 0)
  {
    players_[0].addOpenedCardsToOpenedTop(players_[playerNum]);
    arrowsInsideFlag_ = 0;
    currentTurn_ = playerNum;
    duelWinner_ = playerNum;   
    getTurn();
    if (findWinner() == 0)
    {
      return 0;
    }
    else
    {
      return currentTurn_; 
    }
  }

  //find same cards
  bool sameFound = false;
  int currentCard = players_[playerNum].getTopCardID();
  if(currentCard != -1)
  {
    for (int i = 1; i <= playersNumber_; ++i)
    {
      if ((i != playerNum) && (currentCard == players_[i].getTopCardID()))
      {
        PlayerModel &looser = players_[i];
        looser.addOpenedCardsToClosedBottom(looser);
        looser.addOpenedCardsToClosedBottom(players_[playerNum]);
        looser.addOpenedCardsToClosedBottom(players_[0]);
        currentTurn_ = i;
        getTurn();
        sameFound = true;
        duelWinner_ = playerNum;
        duelLooser_ = i;
        break;
      }
    }
  }

  if (!sameFound)
  { 
    duelStarted_ = false;
    wrongDuelist_ = playerNum;
    PlayerModel &looser = players_[playerNum];
    for (int i = 0; i <= playersNumber_; ++i)
    {
      looser.addOpenedCardsToClosedBottom(players_[i]);
    }
  }

  //find winner
  if (findWinner() == 0)
  {
    return 0;
  }
  else
  {
    return currentTurn_; 
  }
}


int GameModel::startGame(bool toShuffle)
{
  if (toShuffle)
  {
    shuffle();
  }
  distribute();
  isGameStarted_ = true;
  return currentTurn_;
}


int GameModel::getOpenedCardsNumber(int playerNum) const
{
  return players_[playerNum].getOpenedCardsNumber();
}

int GameModel::getClosedCardsNumber(int playerNum) const
{
  return players_[playerNum].getClosedCardsNumber();
}

int GameModel::getWhoIsWinner() const
{
  return whoIsWinner_;
}

int GameModel::getPlayersNumber() const
{
  return playersNumber_;
}

bool GameModel::isGameStarted() const
{
  return isGameStarted_;
}

int GameModel::getCurrentTurn() const
{
  return currentTurn_;
}


int GameModel::getTopCardID(int seat) const
{
  if ((seat > playersNumber_) || (seat <= 0))
  {
    return -1;
  }  
  return players_[seat].getTopCardID();
}

int GameModel::getTopCardColor(int seat) const
{
  if ((seat > playersNumber_) || (seat <= 0))
  {
    return -1;
  }  
  return players_[seat].getTopCardColor();
  
}

const std::string& GameModel::getPlayerName(int seat) const
{  
  return players_[seat].getName();
}


int GameModel::getArrowsInsideFlag() const
{
  return arrowsInsideFlag_;
}

const std::vector<Card>& GameModel::getCards() const
{
  return cards_;
}

void GameModel::setCards(const std::vector<Card>& cards)
{
  std::copy(cards.begin(), cards.end(), cards_.begin());
}

int GameModel::getDuelWinner()
{
  return duelWinner_;
}

int GameModel::getDuelLooser()
{
  return duelLooser_;
}

int GameModel::getWrongDuelist()
{
  return wrongDuelist_;
}
